package com.aaa.config;

import com.aaa.util.DefaultMsg;
import com.google.gson.Gson;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;

import javax.annotation.Resource;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

/**
 * spring securitg的配置类
 */
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class MySecurityConfig extends WebSecurityConfigurerAdapter {


    @Resource
    private MyUserDetailsServiceImpl userDetailsService;
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //声明一个空的权限集合
        //List<? extends GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
        //auth.使用内存认证的方式.指定用户名.指定密码.指定空权限集合
        //auth.inMemoryAuthentication().withUser("lisi").password("$2a$10$Kg8DvqSlk2bDkU5GSfJuZehOuOQPOOStDueKKyR5mpjuJDOc4Dsjm")
        //.authorities(authorities)
        //.和.配置1密码加密的方式为不加密码
        //.and().passwordEncoder(NoOpPasswordEncoder.getInstance())
        ;
        //使用UserDetailsService的接口实现类对象去加载密码信息
        auth.userDetailsService(userDetailsService);
    }

    /**
     * 密码加密的方式2 往spring 容器中放一个 PasswordEncoder
     *  这样，在spring security 框架校验密码的时候会自己去使用这个对象
     * @return
     */
    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        //http. 需要启动登录校验（认证）
        //对于这个方法传递的路径.不需要登录也能访问
        // 其它任何请求.都需要登录校验
        http.authorizeRequests().mvcMatchers("/**").permitAll().anyRequest().authenticated()
                //并且.使用from的方式进行登录
                .and().formLogin().loginPage("/toLogin").permitAll()
                //用户名参数的名称 默认值是username
                .usernameParameter("username")
                //密码参数名称 默认值是password
                .passwordParameter("password")
                //指定访问登录请求的路径  这个路径如果你不配置 和跳转到登录界面的路径是一致的
                //但是post请求 ，如果配置了 就是这个路径
                .loginProcessingUrl("/checkUser")
                //配置直接登录的时候登录成功默认跳转到的路径 默认值是/
                .defaultSuccessUrl("/toIndex")
                //登录成功的处理方式 如果不配置 匿名内部类
                .successHandler(new AuthenticationSuccessHandler(){

                    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
                        DefaultMsg defaultMsg =new DefaultMsg();
                        response.setContentType("application/json;charset=UTF-8");
                        //把defaultMsg转成json字符串
                        String json = new Gson().toJson(defaultMsg);
                        PrintWriter writer = response.getWriter();
                        writer.print(json);
                        writer.close();

                    }
                })
//                用户登录失败的处理方式 如果不配置 跳转到登录界面
                .failureHandler(new AuthenticationFailureHandler() {
                    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) throws IOException, ServletException {
                        DefaultMsg defaultMsg =new DefaultMsg();
                        defaultMsg.setSuccess(0);
                        defaultMsg.setError("用户名或者密码错误");
                        response.setContentType("application/json;charset=UTF-8");
                        //把defaultMsg转成json字符串
                        String json = new Gson().toJson(defaultMsg);
                        PrintWriter writer = response.getWriter();
                        writer.print(json);
                        writer.close();
                    }
                })
        //配置退出登录的路径 如果不配置路径/logout
         .and().logout().logoutUrl("/toLogout")
        //退出登录之后要想干一些别的事 可以指定这个路径
         .logoutSuccessUrl("/logoutSuccess").permitAll();
        ;

        //禁用csrf
        http.csrf().disable();
        //禁用spring security的iframe保护策略
        http.headers().frameOptions().disable();
        //允许security跨域
        http.cors();
        //配如果用户没有登录  返回json字符串  默认行为是跳转到登录界面
        http.exceptionHandling()
//                .authenticationEntryPoint(new AuthenticationEntryPoint() {
//            public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) throws IOException, ServletException {
//                DefaultMsg defaultMsg =new DefaultMsg();
//                defaultMsg.setCode(401);
//                defaultMsg.setSuccess(0);
//                defaultMsg.setError("用户没有登录");
//                response.setContentType("application/json;charset=UTF-8");
//                //把defaultMsg转成json字符串
//                String json = new Gson().toJson(defaultMsg);
//                PrintWriter writer = response.getWriter();
//                writer.print(json);
//                writer.close();
//            }
//        })

                //如果没有权限  返回json字符串 默认的行为是返回403状态码
                .accessDeniedHandler(new AccessDeniedHandler() {
                    public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException e) throws IOException, ServletException {
//                DefaultMsg defaultMsg =new DefaultMsg();
//                defaultMsg.setCode(403);
//                defaultMsg.setSuccess(0);
//                defaultMsg.setError("用户没有权限");
//                response.setContentType("application/json;charset=UTF-8");
//                //把defaultMsg转成json字符串
//                String json = new Gson().toJson(defaultMsg);
//                PrintWriter writer = response.getWriter();
//                writer.print(json);
//                writer.close();
                        request.getRequestDispatcher("/WEB-INF/jsp/noPermit.jsp").forward(request,response);
                    }
                })

        ;
    }


    @Override
    public void configure(WebSecurity web) {
        //配置不拦截 静态资源
        web.ignoring().mvcMatchers("/scripts/**");
    }

    public static void main(String[] args) {
        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
        String encode = bCryptPasswordEncoder.encode("654321");
        System.out.println(encode);
    }
}
